package cn.bbstone.pisces2.config;

import cn.bbstone.pisces2.comm.Const;
import cn.hutool.core.io.resource.UrlResource;

import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;

public class ConfigFactory {
    private static final String FACTORIES_RESOURCE_LOCATION = "META-INF/bbstone.factories";
    private static final String SERVER_KEY = "server";
    private static final String CLIENT_KEY = "client";

    public static ConfigModel loadConfigs(String serverOrClient) {
//        Thread.currentThread().getContextClassLoader()
        return loadConfigs(null, serverOrClient);
    }

    public static ConfigModel loadConfigs(ClassLoader classLoader, String serverOrClient) {
        classLoader = ConfigFactory.class.getClassLoader();
        ConfigModel configModel = null;
        Properties props = null;
        try {
            Enumeration<URL> urls = (classLoader != null ?
                    classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                    ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();

                props = new Properties();
                if ("bundleresource".equals(url.getProtocol())) {
                    // ---- run as eclipse bundle
                    // bundleresource://126.fwk151694843/META-INF/bbstone.factories
                    InputStream inputStream = url.openStream();
                    props.load(inputStream);
                } else { // run as normal jar
                    UrlResource resource = new UrlResource(url);
                    props.load(new FileReader(resource.getFile())); // new File(uri)
                }
                String implClassName = null;
                if (Const.SERVER.equals(serverOrClient)) {
                    implClassName = props.getProperty(SERVER_KEY);
                } else {
                    implClassName = props.getProperty(CLIENT_KEY);
                }
//                Config config = loadClass(implClassName);
                Class<?> configClass = classLoader.loadClass(implClassName);
                Config config = (Config)configClass.getConstructor().newInstance();
                if ("bundleresource".equals(url.getProtocol())) {
                    configModel = config.load(serverOrClient, classLoader);
                } else {
                    configModel = config.load(serverOrClient, null);
                }
//                for (Map.Entry<?, ?> entry : props.entrySet()) {
//                    String factoryClassName = ((String) entry.getKey()).trim();
//                    String implClassName = (String) entry.getValue();
//                    Class<?> clazz = Class.forName(implClassName.trim());
//                    Config config = (Config) clazz.getDeclaredConstructor().newInstance();
//                    config.load();
//                }
            }
        } catch (IOException | ClassNotFoundException | NoSuchMethodException ex) {
            throw new IllegalArgumentException("Unable to load factories from location [" +
                    FACTORIES_RESOURCE_LOCATION + "]", ex);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return configModel;
    }

    private static Config loadClass(String implClassName) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class<?> clazz = Class.forName(implClassName.trim());
        Config config = (Config) clazz.getDeclaredConstructor().newInstance();
        return config;
    }

}
